package io.kwdb.sdk;

/**
 * Configuration for KWDB client. Immutable configuration object with builder pattern for easy
 * construction.
 */
public class Config {

  /** Transport type for client communication. */
  public enum Transport {
    GRPC, // Use gRPC protocol (port 9090 by default)
    ILP // Use InfluxDB Line Protocol over HTTP (port 9091 by default)
  }

  /** Backpressure strategy for batch processing. */
  public enum Backpressure {
    BLOCK, // Block when queue is full (default)
    DROP_OLDEST // Drop oldest items when queue is full
  }

  private final String host;
  private final int port;
  private final int httpPort;
  private final int timeoutMillis;
  private final int batchSize;
  private final int queueCapacity;
  private final boolean enableCompression;
  private final Transport transport;
  private final boolean ilpIntegerWithSuffix;

  // M3: Batch processing and backpressure
  private final int maxBatchSize;
  private final int lingerMs;
  private final int maxQueueSize;
  private final Backpressure backpressure;

  // M3: Retry policy
  private final boolean enableRetry;
  private final int maxRetries;
  private final int baseBackoffMs;

  // M3: Security
  private final boolean tls;
  private final String caCertPath;
  private final String authToken;
  private final String username;
  private final String password;
  private final boolean gzip;

  private Config(Builder builder) {
    this.host = builder.host;
    this.port = builder.port;
    this.httpPort = builder.httpPort;
    this.timeoutMillis = builder.timeoutMillis;
    this.batchSize = builder.batchSize;
    this.queueCapacity = builder.queueCapacity;
    this.enableCompression = builder.enableCompression;
    this.transport = builder.transport;
    this.ilpIntegerWithSuffix = builder.ilpIntegerWithSuffix;

    // M3 fields
    this.maxBatchSize = builder.maxBatchSize;
    this.lingerMs = builder.lingerMs;
    this.maxQueueSize = builder.maxQueueSize;
    this.backpressure = builder.backpressure;
    this.enableRetry = builder.enableRetry;
    this.maxRetries = builder.maxRetries;
    this.baseBackoffMs = builder.baseBackoffMs;
    this.tls = builder.tls;
    this.caCertPath = builder.caCertPath;
    this.authToken = builder.authToken;
    this.username = builder.username;
    this.password = builder.password;
    this.gzip = builder.gzip;
  }

  // Getters
  public String getHost() {
    return host;
  }

  public int getPort() {
    return port;
  }

  public int getTimeoutMillis() {
    return timeoutMillis;
  }

  public int getBatchSize() {
    return batchSize;
  }

  public int getQueueCapacity() {
    return queueCapacity;
  }

  public boolean isEnableCompression() {
    return enableCompression;
  }

  public int getHttpPort() {
    return httpPort;
  }

  public Transport getTransport() {
    return transport;
  }

  public boolean isIlpIntegerWithSuffix() {
    return ilpIntegerWithSuffix;
  }

  // M3 getters
  public int getMaxBatchSize() {
    return maxBatchSize;
  }

  public int getLingerMs() {
    return lingerMs;
  }

  public int getMaxQueueSize() {
    return maxQueueSize;
  }

  public Backpressure getBackpressure() {
    return backpressure;
  }

  public boolean isEnableRetry() {
    return enableRetry;
  }

  public int getMaxRetries() {
    return maxRetries;
  }

  public int getBaseBackoffMs() {
    return baseBackoffMs;
  }

  public boolean isTls() {
    return tls;
  }

  public String getCaCertPath() {
    return caCertPath;
  }

  public String getAuthToken() {
    return authToken;
  }

  public String getUsername() {
    return username;
  }

  public String getPassword() {
    return password;
  }

  public boolean isGzip() {
    return gzip;
  }

  // Static factory method
  public static Builder builder() {
    return new Builder();
  }

  // Builder class
  public static class Builder {
    private String host = "127.0.0.1";
    private int port = 9090;
    private int httpPort = 9091;
    private int timeoutMillis = 30000; // 30 seconds default
    private int batchSize = 1000;
    private int queueCapacity = 10000;
    private boolean enableCompression = false;
    private Transport transport = Transport.GRPC;
    private boolean ilpIntegerWithSuffix = true;

    // M3: Batch processing defaults
    private int maxBatchSize = 0; // 0 = disabled (direct write)
    private int lingerMs = 0; // 0 = no wait
    private int maxQueueSize = 10000;
    private Backpressure backpressure = Backpressure.BLOCK;

    // M3: Retry policy defaults
    private boolean enableRetry = true;
    private int maxRetries = 3;
    private int baseBackoffMs = 100;

    // M3: Security defaults
    private boolean tls = false;
    private String caCertPath = null;
    private String authToken = null;
    private String username = null;
    private String password = null;
    private boolean gzip = false;

    public Builder host(String host) {
      if (host == null || host.isEmpty()) {
        throw new IllegalArgumentException("Host cannot be null or empty");
      }
      this.host = host;
      return this;
    }

    public Builder port(int port) {
      if (port < 1 || port > 65535) {
        throw new IllegalArgumentException("Port must be between 1 and 65535");
      }
      this.port = port;
      return this;
    }

    public Builder timeoutMillis(int timeoutMillis) {
      if (timeoutMillis < 0) {
        throw new IllegalArgumentException("Timeout cannot be negative");
      }
      this.timeoutMillis = timeoutMillis;
      return this;
    }

    public Builder batchSize(int batchSize) {
      if (batchSize < 1) {
        throw new IllegalArgumentException("Batch size must be at least 1");
      }
      this.batchSize = batchSize;
      return this;
    }

    public Builder queueCapacity(int queueCapacity) {
      if (queueCapacity < 1) {
        throw new IllegalArgumentException("Queue capacity must be at least 1");
      }
      this.queueCapacity = queueCapacity;
      return this;
    }

    public Builder enableCompression(boolean enableCompression) {
      this.enableCompression = enableCompression;
      return this;
    }

    public Builder httpPort(int httpPort) {
      if (httpPort < 1 || httpPort > 65535) {
        throw new IllegalArgumentException("HTTP port must be between 1 and 65535");
      }
      this.httpPort = httpPort;
      return this;
    }

    public Builder transport(Transport transport) {
      if (transport == null) {
        throw new IllegalArgumentException("Transport cannot be null");
      }
      this.transport = transport;
      return this;
    }

    public Builder ilpIntegerWithSuffix(boolean ilpIntegerWithSuffix) {
      this.ilpIntegerWithSuffix = ilpIntegerWithSuffix;
      return this;
    }

    // M3 builder methods
    public Builder maxBatchSize(int maxBatchSize) {
      if (maxBatchSize < 0) {
        throw new IllegalArgumentException("Max batch size cannot be negative");
      }
      this.maxBatchSize = maxBatchSize;
      return this;
    }

    public Builder lingerMs(int lingerMs) {
      if (lingerMs < 0) {
        throw new IllegalArgumentException("Linger ms cannot be negative");
      }
      this.lingerMs = lingerMs;
      return this;
    }

    public Builder maxQueueSize(int maxQueueSize) {
      if (maxQueueSize < 1) {
        throw new IllegalArgumentException("Max queue size must be at least 1");
      }
      this.maxQueueSize = maxQueueSize;
      return this;
    }

    public Builder backpressure(Backpressure backpressure) {
      if (backpressure == null) {
        throw new IllegalArgumentException("Backpressure cannot be null");
      }
      this.backpressure = backpressure;
      return this;
    }

    public Builder enableRetry(boolean enableRetry) {
      this.enableRetry = enableRetry;
      return this;
    }

    public Builder maxRetries(int maxRetries) {
      if (maxRetries < 0 || maxRetries > 10) {
        throw new IllegalArgumentException("Max retries must be between 0 and 10");
      }
      this.maxRetries = maxRetries;
      return this;
    }

    public Builder baseBackoffMs(int baseBackoffMs) {
      if (baseBackoffMs < 0) {
        throw new IllegalArgumentException("Base backoff ms cannot be negative");
      }
      this.baseBackoffMs = baseBackoffMs;
      return this;
    }

    public Builder tls(boolean tls) {
      this.tls = tls;
      return this;
    }

    public Builder caCertPath(String caCertPath) {
      this.caCertPath = caCertPath;
      return this;
    }

    public Builder authToken(String authToken) {
      this.authToken = authToken;
      return this;
    }

    public Builder username(String username) {
      this.username = username;
      return this;
    }

    public Builder password(String password) {
      this.password = password;
      return this;
    }

    public Builder gzip(boolean gzip) {
      this.gzip = gzip;
      return this;
    }

    public Config build() {
      return new Config(this);
    }
  }

  @Override
  public String toString() {
    return "Config{"
        + "host='"
        + host
        + '\''
        + ", port="
        + port
        + ", httpPort="
        + httpPort
        + ", timeoutMillis="
        + timeoutMillis
        + ", batchSize="
        + batchSize
        + ", queueCapacity="
        + queueCapacity
        + ", enableCompression="
        + enableCompression
        + ", transport="
        + transport
        + ", ilpIntegerWithSuffix="
        + ilpIntegerWithSuffix
        + '}';
  }
}
